package com.woniuxy.portal.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.IdUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.woniuxy.portal.common.constant.OrderStatusEnum;
import com.woniuxy.portal.common.enums.impl.BusinessCode;
import com.woniuxy.portal.common.exception.Asserts;
import com.woniuxy.portal.common.exception.BusinessException;
import com.woniuxy.portal.entity.Address;
import com.woniuxy.portal.entity.Book;
import com.woniuxy.portal.entity.Item;
import com.woniuxy.portal.entity.Order;
import com.woniuxy.portal.mapper.AddressMapper;
import com.woniuxy.portal.mapper.BookMapper;
import com.woniuxy.portal.mapper.ItemMapper;
import com.woniuxy.portal.mapper.OrderMapper;
import com.woniuxy.portal.model.vo.CardVo;
import com.woniuxy.portal.model.vo.CartItemVo;
import com.woniuxy.portal.model.vo.OrderItemVo;
import com.woniuxy.portal.model.vo.OrderVo;
import com.woniuxy.portal.service.IOrderService;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.stream.Collectors;

@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements IOrderService {

    @Autowired
    private ItemMapper itemMapper;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Autowired
    private AddressMapper addressMapper;
    @Autowired
    private BookMapper bookMapper;
    @Autowired
    private RedissonClient redissonClient;

    @Override
    @Transactional
    public void submitOrder(Integer userId, Integer addressId, CardVo cardVo, String orderNum) {

        // 生产订单ID: 雪花算法生成
        // 参数1 机器id； 参数2：机房id
        Snowflake snowflake = IdUtil.getSnowflake(1, 1);
        long orderId = snowflake.nextId();

        // 保存订单明细
        List<CartItemVo> cartItemVos = cardVo.getCartItemVos();
        cartItemVos.forEach(cartItemVo -> {

            // =============使用Redission实现分布式锁，解决超卖问题==================
            // 【获取分布式锁对象】
            RLock rLock = redissonClient.getLock("Lock_" + cartItemVo.getId());
            try {
                // 【加锁】
                rLock.lock();
                // 库存是否充足？
                Integer storeCount = (Integer) redisTemplate.opsForHash().get("storage", cartItemVo.getId() + "");
                Asserts.error(cartItemVo.getBuycount() > storeCount, BusinessCode.STORAGE_IS_NOT_ENOUGH);
                // 库存充足，扣减库存
                redisTemplate.opsForHash().increment("storage", cartItemVo.getId() + "", -cartItemVo.getBuycount());
            } catch (Exception e) {
                throw new BusinessException(BusinessCode.STORAGE_IS_NOT_ENOUGH);
            } finally {
                // 【释放锁】
                rLock.unlock();
            }


            // 订单明细
            Item item = new Item();
            item.setBookId(cartItemVo.getId());
            item.setBookName(cartItemVo.getName());
            item.setPrice(cartItemVo.getPrice());
            item.setBcount(cartItemVo.getBuycount());
            item.setSumprice(cartItemVo.getSumPrice());
            item.setOrderId(orderId); // 引用订单ID
            item.setCreatetime(new Date());
            itemMapper.insert(item);
        });
        // 保存订单
        Order order = new Order();
        order.setId(orderId);
        order.setOrderNum(orderNum);
        order.setTotalprice(cardVo.getTotalPrice());
        order.setUserId(userId.longValue());
        order.setAddressId(addressId);
        order.setCreatetime(new Date());
        order.setState(OrderStatusEnum.NO_PAY.getCode());
        this.save(order);

        // 因为清空购物车需要用到userId, 购物车：user_cart_1（userId）
        cardVo.setUserId(userId);

        //mq普通队列： 解决异步清空购物车问题
        rabbitTemplate.convertAndSend("clearBuyCartQueue", JSONUtil.toJsonStr(cardVo));

        //mq延迟队列： 解决超时未支付问题
        rabbitTemplate.convertAndSend("order-exchange","order.key.normal", JSONUtil.toJsonStr(order));
    }

    @Override
    public List<OrderVo> queryWaitPayOrder(Integer userId) {

        //返回我的待支付订单: SELECT * FROM t_order WHERE userId=1 AND state=1
        List<Order> orders = baseMapper.selectList(Wrappers.lambdaQuery(Order.class)
                .eq(Order::getUserId, userId)
                .eq(Order::getState,OrderStatusEnum.NO_PAY.getCode()));

        List<OrderVo> orderVos = orders.stream().map(order -> {
            //将订单对象，转换为订单视图对象
            OrderVo orderVO = BeanUtil.copyProperties(order, OrderVo.class);
            //遍历枚举，将状态码转换为 对应的描述信息
            orderVO.setOrderStatus(this.getOrderStatus(order.getState()));//订单状态

            //查询地址对象（此处：可以使用缓存优化）
            Address address = addressMapper.selectById(order.getAddressId());
            orderVO.setReceiver(address.getReciver());//收货人

            //订单明细: select * from t_item where orderId=订单ID
            List<Item> items = itemMapper.selectList(Wrappers.lambdaQuery(Item.class).
                    eq(Item::getOrderId,order.getId()));

            List<OrderItemVo> orderItems = items.stream().map(i -> {
                OrderItemVo orderItemVO = BeanUtil.copyProperties(i, OrderItemVo.class);
                //根据图书的ID，查询图书，获得图片地址（此处：可以使用缓存优化）
                Book book = bookMapper.selectById(i.getBookId());
                orderItemVO.setBookImg(book.getImgsrc());
                return orderItemVO;
            }).collect(Collectors.toList());

            orderVO.setOrderItem(orderItems);//订单明细
            return orderVO;
        }).collect(Collectors.toList());
        return orderVos;
    }

    private String getOrderStatus(Integer code){
        for(OrderStatusEnum e :OrderStatusEnum.values()){
            if(e.getCode() == code){
                return e.getDescribe();
            }
        }
        return null;
    }

    @Override
    public void payOrder(Long orderId) {
        //1. 修改订单id，修改订单状态
        Order order = baseMapper.selectById(orderId);
        order.setState(OrderStatusEnum.NO_SEND.getCode());
        baseMapper.updateById(order);

        //2. 修改数据库中库存
        //2.1 根据订单id，查询订单详情
        List<Item> items = itemMapper.selectList(
                Wrappers.lambdaQuery(Item.class).eq(Item::getOrderId, orderId));
        items.forEach(item -> {
            //2.2 根据图书id查询
            Book book = bookMapper.selectById(item.getBookId());
            //2.2 修改库存、购买数量
            book.setStorecount(book.getStorecount() - item.getBcount());
            book.setBuycount(book.getBuycount() + item.getBcount());
            bookMapper.updateById(book);
        });
    }
}
